package com.szl.yeb.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.szl.yeb.common.constant.MailConstant;
import com.szl.yeb.entity.*;
import com.szl.yeb.mapper.*;
import com.szl.yeb.service.EmployeeService;
import com.szl.yeb.utils.ListToMapUtil;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.szl.yeb.common.PageResult;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.szl.yeb.utils.MybatisPlusUtil;

import java.text.DecimalFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

/**
 * (Employee)表服务实现类
 *
 * @author szl
 * @since 2022-08-24 16:21:24
 */
@Service("employeeService")
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements EmployeeService {

    @Autowired
    private NationMapper nationMapper;

    @Autowired
    private JoblevelMapper joblevelMapper;

    @Autowired
    private DepartmentMapper departmentMapper;

    @Autowired
    private PoliticsStatusMapper politicsStatusMapper;

    @Autowired
    private PositionMapper positionMapper;

    @Autowired
    private SalaryMapper salaryMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private MailLogMapper mailLogMapper;

    @Override
    public PageResult getPage(Integer currentPage, Integer size, Employee employee, LocalDate[] engageDateScope) {
        Page<Employee> page = new Page<>(currentPage, size);

        QueryWrapper<Employee> queryWrapper = MybatisPlusUtil.queryWrapperBuilder(employee);

        if (engageDateScope != null && engageDateScope.length > 0) {
            queryWrapper.between("beginDate", engageDateScope[0], engageDateScope[1]);
        }

        this.page(page, queryWrapper);

        List<Employee> employees = page.getRecords();

        return new PageResult((int) page.getTotal(), fillEmployees(employees));

    }

    @Override
    public String getMaxWorkId() {
        int maxWordId = Integer.parseInt((String) baseMapper.selectMaps(MybatisPlusUtil.getQWrapper(Employee.class).select("max(workID)")).get(0).get("max(workID)"));
        return String.format("%08d", maxWordId + 1);
    }

    @Override
    public List<Employee> getFilledEmployees() {
        List<Employee> employees = this.list();
        return fillEmployees(employees);
    }

    @Override
    public Employee getFilledEmployeeById(Integer id) {

        List<Employee> employees = new ArrayList<>();
        employees.add(baseMapper.selectById(id));
        return fillEmployees(employees).get(0);
    }

    @Override
    public PageResult getPage(Integer currentPage, Integer size) {
        return getPage(currentPage, size, new Employee(), new LocalDate[0]);
    }

    @Override
    public Boolean addEmployee(Employee employee) {
        LocalDate beginContract = employee.getBeginContract();
        LocalDate endContract = employee.getEndContract();
        long days = beginContract.until(endContract, ChronoUnit.DAYS);
        DecimalFormat decimalFormat = new DecimalFormat("##.00");
        employee.setContractTerm(Double.parseDouble(decimalFormat.format(days / 365.00)));

        this.save(employee);

        List<Employee> employees = new ArrayList<>();
        employees.add(employee);

        String msgId = UUID.randomUUID().toString();

        MailLog mailLog = new MailLog();
        mailLog.setMsgId(msgId)
                .setEid(employee.getId())
                .setStatus(0)
                .setRouteKey(MailConstant.MAIL_ROUTING_KEY_NAME)
                .setExchange(MailConstant.MAIL_EXCHANGE_NAME)
                .setCount(0)
                .setTryTime(LocalDateTime.now().plusMinutes(MailConstant.MSG_TIMEOUT))
                .setCreateTime(LocalDateTime.now())
                .setUpdateTime(LocalDateTime.now());
        mailLogMapper.insert(mailLog);

        rabbitTemplate.convertAndSend(MailConstant.MAIL_EXCHANGE_NAME, MailConstant.MAIL_ROUTING_KEY_NAME, fillEmployees(employees).get(0), new CorrelationData(msgId));

        return true;
    }

    private List<Employee> fillEmployees(List<Employee> employees) {
        //以下为使用mybatis-plus单表查询替代多表关联查询，虽然代码看起来比较多，但是在数据量很大的情况下，效率优于关联查询

        Set<Integer> nationIds = new HashSet<>();
        Set<Integer> joblevelIds = new HashSet<>();
        Set<Integer> departmentIds = new HashSet<>();
        Set<Integer> politicIds = new HashSet<>();
        Set<Integer> posIds = new HashSet<>();
        Set<Integer> salaryIds = new HashSet<>();

        employees.forEach(item -> {
            nationIds.add(item.getNationId());
            joblevelIds.add(item.getJobLevelId());
            departmentIds.add(item.getDepartmentId());
            politicIds.add(item.getPoliticId());
            posIds.add(item.getPosId());
            salaryIds.add(item.getSalaryId());
        });

        List<Nation> nations = nationMapper.selectList(MybatisPlusUtil.getLQWrapper(Nation.class).in(nationIds.size() > 0, Nation::getId, nationIds));
        Map<Object, Nation> nationMap = ListToMapUtil.list2Map(nations, "id");

        List<Joblevel> joblevels = joblevelMapper.selectList(MybatisPlusUtil.getLQWrapper(Joblevel.class).in(joblevelIds.size() > 0, Joblevel::getId, joblevelIds));
        Map<Object, Joblevel> joblevelMap = ListToMapUtil.list2Map(joblevels, "id");

        List<Department> departments = departmentMapper.selectList(MybatisPlusUtil.getLQWrapper(Department.class).in(departmentIds.size() > 0, Department::getId, departmentIds));
        Map<Object, Department> departmentMap = ListToMapUtil.list2Map(departments, "id");

        List<PoliticsStatus> politicsStatuses = politicsStatusMapper.selectList(MybatisPlusUtil.getLQWrapper(PoliticsStatus.class).in(politicIds.size() > 0, PoliticsStatus::getId, politicIds));
        Map<Object, PoliticsStatus> politicsStatusMap = ListToMapUtil.list2Map(politicsStatuses, "id");

        List<Position> positions = positionMapper.selectList(MybatisPlusUtil.getLQWrapper(Position.class).in(posIds.size() > 0, Position::getId, posIds));
        Map<Object, Position> positionMap = ListToMapUtil.list2Map(positions, "id");

        List<Salary> salaries = salaryMapper.selectList(MybatisPlusUtil.getLQWrapper(Salary.class).in(salaryIds.size() > 0, Salary::getId, salaryIds));
        Map<Object, Salary> salaryMap = ListToMapUtil.list2Map(salaries, "id");

        employees = employees.stream().peek(item -> {
            item.setNation(nationMap.get(item.getNationId()));
            item.setJoblevel(joblevelMap.get(item.getJobLevelId()));
            item.setDepartment(departmentMap.get(item.getDepartmentId()));
            item.setPoliticsStatus(politicsStatusMap.get(item.getPoliticId()));
            item.setPosition(positionMap.get(item.getPosId()));
            item.setSalary(salaryMap.get(item.getSalaryId()));
        }).collect(Collectors.toList());

        return employees;
    }
}

